/**
 * 
 */
package edu.gtcfla.km.platform.service.impl;

import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.vsg.biz.BusinessEntityFactory;
import org.vsg.biz.account.BindingAction;
import org.vsg.biz.account.ModuleFunctoinBindingAction;
import org.vsg.biz.account.Resource;
import org.vsg.biz.account.Url;
import org.vsg.biz.account.repositories.BindingActionRepo;
import org.vsg.biz.account.repositories.ControllerRepo;
import org.vsg.biz.account.repositories.MenuRepo;
import org.vsg.biz.account.repositories.ModuleFunBindingActPermitDefinedRepo;
import org.vsg.biz.account.repositories.ModuleFunctionBindingActRepo;
import org.vsg.biz.account.repositories.ModuleFunctionRepo;
import org.vsg.biz.account.repositories.ModuleRepo;
import org.vsg.biz.account.repositories.PermissionRepo;
import org.vsg.biz.account.repositories.ResourceRepo;
import org.vsg.biz.account.repositories.RoleRepo;
import org.vsg.biz.account.repositories.UrlRepo;
import org.vsg.biz.uid.UnifiedIDProvider;
import org.vsg.common.i18n.I18nMessageService;
import org.vsg.module.resources.ResourceProtocol;
import org.vsg.module.resources.component.Action;
import org.vsg.module.resources.component.AssociationClass;
import org.vsg.module.resources.component.Menu;
import org.vsg.module.resources.component.Module;
import org.vsg.module.resources.component.ModuleFunction;
import org.vsg.module.resources.component.ModuleProxy;
import org.vsg.module.resources.component.PermDefine;
import org.vsg.module.resources.component.Permission;
import org.vsg.module.resources.component.RegisterResource;
import org.vsg.module.resources.component.ResourceRef;
import org.vsg.module.resources.register.ModuleProxyManager;
import org.vsg.module.resources.register.ModuleRegisterManager;
import org.vsg.security.annotation.RegisterRequestPermissionStrategy;

import edu.gtcfla.km.platform.service.SystemHookManager;

/**
 * Init system boot hook handle 
 * @author Bill vison 
 *
 */
public class SystemBootuphookManagerI implements SystemHookManager , InitializingBean {

	@Autowired(required=false)
	private ModuleRegisterManager moduleRegisterManager;	

	@Autowired(required=false)
	private ModuleRepo  moduleRepo;
	
	@Autowired(required=false)
	private ModuleFunctionRepo funRepo;
	
	@Autowired(required=false)
	private MenuRepo  menuRepo;

	@Autowired(required=false)
	private UrlRepo  urlRepo;

	@Autowired(required=false)
	private ControllerRepo ctlRepo;
	
	@Autowired(required=false)
	private PermissionRepo permissionRepo;
	
	@Autowired(required=false)
	private RoleRepo roleRepo;
	
	@Autowired(required=false)
	private ModuleFunctionBindingActRepo moduleFunctionBindingActRepo;
	
	@Autowired(required=false)
	private ModuleFunBindingActPermitDefinedRepo moduleFunBindingActPermitDefinedRepo;
	
	
	@Autowired(required=false)
	private ResourceRepo sysResourceDao;
	
	@Autowired(required=false)
	private BindingActionRepo sysBindingActionDao;	

	@Autowired(required=false)
	private I18nMessageService i18nMessageService;	
	
	@Autowired
	private ModuleProxyManager moduleProxyManager;

	@Autowired(required=false)
	private UnifiedIDProvider unifiedIDProvider;
	
	private ResourceProtocol resourceProtocol = ResourceProtocol.getInstance();

	
	/**
	 * constant user defined 
	 */
	private String initDataUser = "admin00000";
	
	private String initSystemRole = "superadmin";
	
	
	private Map<String , ModuleProxy> proxiesMap = new LinkedHashMap<String, ModuleProxy>();
	
	private static final Logger logger = LoggerFactory.getLogger(SystemBootuphookManagerI.class);
	
	@Autowired
	private BusinessEntityFactory entityFactory;
	
	/**
	 * pre load object 
	 */
	public void afterPropertiesSet() throws Exception {
		
		// --- scan save in jar proper manager ---
		Set<ModuleProxy>  proxies =  moduleProxyManager.listAllModules();
		if (logger.isDebugEnabled()) {
			logger.debug("--- load init module proxies --- ");
			for (ModuleProxy proxy : proxies) {
				logger.debug(" module id  : " + proxy.getProxyId() + " , url: " + proxy.getResources() );
			}
		}
		
		// ---- transaction handle ---
		
		try {
			
			// --- new module ---
			Set<org.vsg.biz.account.Module> modulesToAdd = initUnloadedModules( proxies );
			if ( logger.isDebugEnabled() ) {
				logger.debug("--- find new module in this time --- ");
				for (org.vsg.biz.account.Module mod : modulesToAdd) {
					logger.debug( "mod id: " + mod.getId() + " , " + mod.getCode() );
				}
			}			
			
			// --- add module first ---
			moduleRepo.saveAll( modulesToAdd  );
			
			//  --- find all module ---
			Set<org.vsg.biz.account.Module> allRegModule = moduleRepo.findAll();
			Set<String>  moduleIds = new LinkedHashSet<String>();
			for (org.vsg.biz.account.Module mod : allRegModule) {
				moduleIds.add( mod.getId() );
			}
			
			// --- new function ---
			Set<org.vsg.biz.account.ModuleFunction> funsToAdd = initUnloadedFuns(moduleIds ,  allRegModule);
			if ( logger.isDebugEnabled() ) {
				logger.debug("--- find new function in this time --- ");
				for (org.vsg.biz.account.ModuleFunction fun : funsToAdd) {
					logger.debug( "fun id: " + fun.getId() + " , " + fun.getCode() );
				}			
			}
			
			// --- add function second ---
			funRepo.saveAll(funsToAdd);
			
			// --- find all funs ---
			Map<String , org.vsg.biz.account.ModuleFunction> allFuns =  funRepo.findAllMapByModuleIds( moduleIds );

			// --- new url ---
			Set<Url>  urlsToAdd = initUnloadedUrls(allFuns.keySet() , allRegModule);			

			// --- new controller ---
			Set<org.vsg.biz.account.Controller> ctlsToAdd =  initUnloadedController(modulesToAdd);

	
			Set<ModuleFunctoinBindingAction>  bindingActs = initFunctionBindingAction(funsToAdd);
			if ( logger.isDebugEnabled() ) {
				logger.debug("--- find new binding action in this time --- ");
				for (org.vsg.biz.account.ModuleFunctoinBindingAction bindAct : bindingActs) {
					logger.debug( "bindingAct id: " + bindAct.getBindingActId() + " , " + bindAct.getModFunctionId() );
				}			
			}
			

			Set<org.vsg.biz.account.ModuleFunBindingActPermitDefined> bindingActPermDefs = initFunctionBindingActionPermDefined(bindingActs  , modulesToAdd);
			
						
			// --- new menu ---
			Set<org.vsg.biz.account.Menu> menusToAdd = initUnloadedMenus(new LinkedHashSet<org.vsg.biz.account.ModuleFunction> ( allFuns.values() ), moduleIds);
			
			//--- binding resource defined ---
			Set<Resource> bindingRes = new LinkedHashSet<Resource>();
			bindingRes.addAll(funsToAdd);
			bindingRes.addAll( menusToAdd );
			bindingRes.addAll( urlsToAdd );

			
			Set<BindingAction>  bindingActions = initAndMergeBindingAction(bindingRes , modulesToAdd);
			
			// --- save function action binding ----
			moduleFunctionBindingActRepo.saveAll( bindingActs );
			moduleFunBindingActPermitDefinedRepo.saveAll( bindingActPermDefs );
			
			
			ctlRepo.saveAll(ctlsToAdd);
			urlRepo.saveAll( urlsToAdd );

			menuRepo.saveAll( menusToAdd );
			sysBindingActionDao.saveAll( bindingActions );
	
			Set<org.vsg.biz.account.Permission> perms =  initPermissions(modulesToAdd);
			
			permissionRepo.saveAll( perms);
			
			
		} catch (Exception e) {
			
			e.printStackTrace();
			
		}
		


	}

	
	// --- read module info ---
	private Set<org.vsg.biz.account.Module>  initUnloadedModules(Set<ModuleProxy> proxies) {
		
		Set<String> existedModuleIds = moduleRepo.findAllIds();
	
		Set<org.vsg.biz.account.Module> unModuleRes = new LinkedHashSet<org.vsg.biz.account.Module>();
		
		Calendar cale = Calendar.getInstance();
		
		ModuleProxy proxy = null;
		for (Iterator<ModuleProxy> proxyIter = proxies.iterator() ; proxyIter.hasNext(); ) {
			proxy = proxyIter.next();
			
			proxiesMap.put(proxy.getProxyId(), proxy);
			
			Module unregModule = proxy.getModule();

			if ( existedModuleIds.contains( proxy.getModule().getId()  ) ) {
				proxyIter.remove();
			} else {
				
				// --- add the new resource ---
				org.vsg.biz.account.Module module = entityFactory.create(org.vsg.biz.account.Module.class);
				module.setId( unregModule.getId()  );
				module.setCode( unregModule.getCode() );
				module.setName( unregModule.getDescription() );
				module.setReleaseDate( unregModule.getReleaseDate() );
				module.setDeveloper( unregModule.getDeveloper() );
				module.setRemark( unregModule.getRemark() );
				module.setVersion( unregModule.getVersion() );
				module.setLocked( unregModule.getLocked() );
				module.setGroupId( unregModule.getGroupdId() );
				module.setModuleId( unregModule.getId() );

				if (!unregModule.isEnabledStatus() ) {
					module.setDisabled( (short)1 );
				}
								
				
				// --- add module defined ---
				module.setCreatedDate( cale.getTime() );
				module.setCreatedUserId(initDataUser);
				module.setUpdatedDate( cale.getTime() );
				module.setUpdatedUserId( initDataUser );
				module.setOwnedUserId( initDataUser );
				
				// ---- map the action handle ---
				unModuleRes.add( module );

				
			}		
		
		}

	
		return unModuleRes;
	}
	
	
	private Set<org.vsg.biz.account.ModuleFunctoinBindingAction> initFunctionBindingAction(Set<org.vsg.biz.account.ModuleFunction> unloadFunctions) {
		Set<org.vsg.biz.account.ModuleFunctoinBindingAction> modFunbindingActions = 
				new LinkedHashSet<org.vsg.biz.account.ModuleFunctoinBindingAction>();
		
		for (Iterator<org.vsg.biz.account.ModuleFunction> unloadedIter = unloadFunctions.iterator() ; unloadedIter.hasNext() ; ) {
			org.vsg.biz.account.ModuleFunction unloadModFun = unloadedIter.next();
			ModuleFunction modFun = (ModuleFunction) moduleRegisterManager.getResourceById(unloadModFun.getId(), unloadModFun.getModule().getId() );
			
			ModuleProxy proxy = proxiesMap.get( unloadModFun.getModule().getId() );
			Set<org.vsg.module.resources.component.Action> modActs =  moduleRegisterManager.listActionsInModule( proxy.getModule()  );

			Set<ResourceRef> resRefes =  modFun.getActionBindings();
			for (ResourceRef ref : resRefes) {
				Action act = moduleRegisterManager.getActionInModule(ref.getRefid(), proxy.getModule() );
				
				if (act == null) {
					continue;
				}
				// --- build action object ---
				org.vsg.biz.account.ModuleFunctoinBindingAction
					unloadData = entityFactory.create( org.vsg.biz.account.ModuleFunctoinBindingAction.class );
				unloadData.setBindingActId( act.getId() );
				unloadData.setBindingActName( act.getName() );
				unloadData.setModFunctionId( unloadModFun.getId() );
				modFunbindingActions.add( unloadData );
			}
		}
		
		return modFunbindingActions;
	}
	
	
	private Set<org.vsg.biz.account.ModuleFunBindingActPermitDefined> initFunctionBindingActionPermDefined(Set<org.vsg.biz.account.ModuleFunctoinBindingAction> bindingActs,
			Set<org.vsg.biz.account.Module> unloadModules
			) {
		ResourceProtocol rprotocol = ResourceProtocol.getInstance();
		
		Set<org.vsg.biz.account.ModuleFunBindingActPermitDefined> modFunbindingActPermDefs = 
				new LinkedHashSet<org.vsg.biz.account.ModuleFunBindingActPermitDefined>();		

		for (Iterator<org.vsg.biz.account.Module> unloadedIter = unloadModules.iterator() ; unloadedIter.hasNext() ; ) {
			
			org.vsg.biz.account.Module unloadModule = unloadedIter.next();
			
			ModuleProxy proxy = proxiesMap.get( unloadModule.getId() );

			for (Iterator<org.vsg.biz.account.ModuleFunctoinBindingAction> unloadedActIter = bindingActs.iterator() ; unloadedActIter.hasNext() ; ) {
				org.vsg.biz.account.ModuleFunctoinBindingAction unloadModFunBinAct = unloadedActIter.next();
				
				Module mod = proxy.getModule();
				String bindActId = unloadModFunBinAct.getBindingActId();
				
				boolean sameModule = rprotocol.matchSameModule( mod , bindActId);
				if ( !sameModule) {
					continue;
				}
				Action act = moduleRegisterManager.getActionInModule(unloadModFunBinAct.getBindingActId(), proxy.getModule());

				Set<PermDefine>  permitDefinedSet =  moduleRegisterManager.listPermDefine(act);
				for (PermDefine pd : permitDefinedSet) {
					// --- build action object ---
					org.vsg.biz.account.ModuleFunBindingActPermitDefined
						unloadData = entityFactory.create( org.vsg.biz.account.ModuleFunBindingActPermitDefined.class );
					unloadData.setRefResourceId( pd.getRefId() );
					unloadData.setBindingActId( act.getId() );
					unloadData.setAccessControl( pd.getAcl() );
					
					modFunbindingActPermDefs.add( unloadData );
				}
				
			}				
			
		}
		
		
		return modFunbindingActPermDefs;
	}
	
	private Set<org.vsg.biz.account.Controller> initUnloadedController(Set<org.vsg.biz.account.Module> unloadModules) {
		Set<org.vsg.biz.account.Controller> ctls = 
				new LinkedHashSet<org.vsg.biz.account.Controller>();
		
		Calendar cale = Calendar.getInstance();

		// --- interate unload module ---
		for (Iterator<org.vsg.biz.account.Module> unloadedIter = unloadModules.iterator() ; unloadedIter.hasNext() ; ) {
			
			org.vsg.biz.account.Module unloadModule = unloadedIter.next();
			ModuleProxy proxy = proxiesMap.get( unloadModule.getId() );
			Set<org.vsg.module.resources.component.Controller> modCtls =  moduleRegisterManager.listControllersInModule( proxy.getModule()  );

			
			for (org.vsg.module.resources.component.Controller ctl : modCtls) {
				org.vsg.biz.account.Controller
				unloadData = entityFactory.create( org.vsg.biz.account.Controller.class );
				unloadData.setId( ctl.getId());
				unloadData.setCode( ctl.getId().replace("ctl:", "") );
				unloadData.setValue( ctl.getValue() );

				unloadData.setModuleId(  proxy.getModule().getId() );
				
				
				if ( ! (proxy.getModule().isEnabledStatus() && proxy.getModule().isBootup() ) ) {
					unloadData.setDisabled( (short)1 );
				} 

				unloadData.setCreatedDate( cale.getTime() );
				unloadData.setCreatedUserId(initDataUser);
				unloadData.setUpdatedDate( cale.getTime() );
				unloadData.setUpdatedUserId( initDataUser );
				unloadData.setOwnedUserId(initDataUser );					
				
				ctls.add( unloadData );
				
			}
			
		}
		
		
		return ctls;		
	}
	
	private Set<org.vsg.biz.account.ModuleFunction> initUnloadedFuns(Set<String> moduleIds , Set<org.vsg.biz.account.Module> regModules) {
		Set<org.vsg.biz.account.ModuleFunction> funs = 
				new LinkedHashSet<org.vsg.biz.account.ModuleFunction>();
		
		
		Map<String, org.vsg.biz.account.ModuleFunction>  funMap = funRepo.findAllMapByModuleIds(moduleIds);
		
		Set<String> funIds = funMap.keySet();

		Calendar cale = Calendar.getInstance();

		// --- interate unload module ---
		for (Iterator<org.vsg.biz.account.Module> unloadedIter = regModules.iterator() ; unloadedIter.hasNext() ; ) {
			
			org.vsg.biz.account.Module regModule = unloadedIter.next();
			ModuleProxy proxy = proxiesMap.get( regModule.getId() );
			
			if (proxy == null) {
				continue;
			}

			Set<ModuleFunction> modFuns = moduleRegisterManager.listFunsInMoudle(  proxy.getModule() );
			
			for (ModuleFunction function : modFuns) {
				
				if(funIds.contains( function.getId() )  ) {
					continue;
				}
				
				org.vsg.biz.account.ModuleFunction
				mra = entityFactory.create( org.vsg.biz.account.ModuleFunction.class );
				mra.setId( function.getId() );
				mra.setName( function.getName() );
				mra.setCode( function.getId().replace("fun:", "") );
				
				mra.setModule( regModule );
				
				mra.setLocked( function.getLocked() );
				mra.setModuleId(  regModule.getId() );
				
				
				if ( ! (proxy.getModule().isEnabledStatus() && proxy.getModule().isBootup() ) ) {
					mra.setDisabled( (short)1 );
				} 

				mra.setCreatedDate( cale.getTime() );
				mra.setCreatedUserId(initDataUser);
				mra.setUpdatedDate( cale.getTime() );
				mra.setUpdatedUserId( initDataUser );
				mra.setOwnedUserId(initDataUser );					
				
				funs.add( mra );
				
			}
			
		}
		
		
		return funs;
	}

	// --- load unreg menu ---
	private Set<org.vsg.biz.account.Menu> initUnloadedMenus(Set<org.vsg.biz.account.ModuleFunction> funs ,Set<String> regModulesIds ) {
		
		Map<String, org.vsg.biz.account.Menu> existedMenus =  this.menuRepo.findAllMapByModuleIds( regModulesIds );
		
		//Set<SysMenu> moduleMenus = new LinkedHashSet<SysMenu>();
		Set<org.vsg.biz.account.Menu> modMenus = new LinkedHashSet<org.vsg.biz.account.Menu>();
		
		Set<String> existedMenuCodes = new LinkedHashSet<String>( existedMenus.keySet() );

		org.vsg.biz.account.Menu moduleMenu = null;
		
		Calendar cale = Calendar.getInstance();
		
		// --- defind parent menu mapping 
		Map<String , Set<org.vsg.biz.account.Menu>> parentMnuGroup 
			= new LinkedHashMap<String , Set<org.vsg.biz.account.Menu>>();
		
		Map<String , String> mnuParentKeyMap = new LinkedHashMap<String , String>();
		
		Map<String , org.vsg.biz.account.Menu> newMenuMap = new LinkedHashMap<String , org.vsg.biz.account.Menu>();

		for (Iterator<String> regModIter = regModulesIds.iterator() ; regModIter.hasNext() ; ) {
			
			String regModId = regModIter.next();
			ModuleProxy proxy = proxiesMap.get( regModId );
			
			if (proxy == null) {
				continue;
			}

			// --- new sub menu ---
			Set<ModuleFunction> modFuns = moduleRegisterManager.listFunsInMoudle( proxy.getModule() );
			
			// --- search function ----
			// --- load menu binding function ---
			for (Iterator<ModuleFunction> unloadedFunIter = modFuns.iterator() ; unloadedFunIter.hasNext() ; ) {
				
				ModuleFunction modFun = unloadedFunIter.next();
				
				// --- find match function key --
				String uuidForFun = null;
				for (org.vsg.biz.account.ModuleFunction fun : funs) {
					if (fun.getId().equals( modFun.getId() ) ) {
						uuidForFun = fun.getId();
					}
				}
				
				// --- search menu by function ---
				Set<Menu> menus = moduleRegisterManager.listMenusInFunction( modFun);

				for (Menu menu : menus) {
					
					// --- check the menu exist ---
					if (existedMenuCodes.contains( menu.getId() )) {
						continue;
					}
					
					org.vsg.biz.account.Menu newMenu = entityFactory.create( org.vsg.biz.account.Menu.class );
					newMenu.setId( menu.getId() );
					newMenu.setCode( menu.getId().replace("mnu:", "") );
					String i18nName = i18nMessageService.getMessage( menu.getI18nCode() , null);
					
					
					newMenu.setFunctionId( uuidForFun );
					newMenu.setName( i18nName == null ? menu.getDescription() : i18nName );
					newMenu.setLocked( menu.getLocked() );
					newMenu.setModuleId( regModId );

					if ( ! (proxy.getModule().isEnabledStatus() && proxy.getModule().isBootup() ) ) {
						newMenu.setDisabled( (short)1 );
					} 
					
					if (menu.isModuleMenu()) {
						newMenu.setModuleMenu(  (short)1  );
						moduleMenu = newMenu;
					}
					
					newMenu.setCreatedDate( cale.getTime() );
					newMenu.setCreatedUserId(initDataUser);
					newMenu.setUpdatedDate( cale.getTime() );
					newMenu.setUpdatedUserId(initDataUser);
					newMenu.setOwnedUserId( initDataUser );				

					
					// --- get the same parent group ---					
					try {
						if (menu.getParentId()  != null && !menu.getParentId().trim().equals("")) {
							// --- get parent menu for parent id ---
							org.vsg.biz.account.Menu parentMenu = existedMenus.get(menu.getParentId() );
							if (parentMenu != null) {
								int menuLevel = parentMenu.getMenuLevel() + 1;
								String treeMap = parentMenu.getTreeMap() == null ? "" : parentMenu.getTreeMap();
								if (treeMap != null && treeMap.length() > 0 ) {
									treeMap += "-";
								}
								treeMap += newMenu.getId();
							} else {

								mnuParentKeyMap.put( newMenu.getId() , menu.getParentId() );
								
								Set<org.vsg.biz.account.Menu> theSameGroup = parentMnuGroup.get( menu.getParentId() );
								if (theSameGroup == null) {
									theSameGroup = new LinkedHashSet<org.vsg.biz.account.Menu>();
								}
								theSameGroup.add(newMenu);
								parentMnuGroup.put( menu.getParentId() , theSameGroup);	
								
							}
							
						}
						
						if (!newMenuMap.keySet().contains( newMenu.getId() )) {
							newMenuMap.put( newMenu.getId() , newMenu);
						}


					
					} finally {
						
					}
					
					
					// --- map the ref-key ---
					if (!menu.isModuleMenu()) {
						ResourceRef  bindingRef =  menu.getRefKey();
						if (bindingRef != null) {
							RegisterResource menuRegRes =  moduleRegisterManager.getResourceById( bindingRef.getRefid() , proxy.getModule().getId());
							if (menuRegRes != null) {
								newMenu.setKeyAction( resourceProtocol.encodeKeyAction(menuRegRes) );
							}
						}
					}

					
					modMenus.add( newMenu );
					existedMenuCodes.add( newMenu.getId() );

				}
				
					
			}
			
			
			// ---- find menu which filter in function and only in module---
			Set<Menu> menus = moduleRegisterManager.listMenusInModule( proxy.getModule() );
			
			for (Menu menu : menus) {
				
				if (existedMenuCodes.contains( menu.getId() )) {
					continue;
				}
				
				org.vsg.biz.account.Menu subMenu = entityFactory.create( org.vsg.biz.account.Menu.class );
				subMenu.setId( menu.getId() );
				subMenu.setCode( menu.getId().replace("mnu:", "") );
				String i18nName = i18nMessageService.getMessage( menu.getI18nCode() , null);
				
				
				subMenu.setFunctionId( null );
				subMenu.setName( i18nName == null ? menu.getDescription() : i18nName );
				subMenu.setLocked( menu.getLocked() );
				subMenu.setModuleId( regModId );

				if ( ! (proxy.getModule().isEnabledStatus() && proxy.getModule().isBootup() ) ) {
					subMenu.setDisabled( (short)1 );
				} 
				if (menu.isModuleMenu()) {
					subMenu.setModuleMenu(  (short)1  );
					moduleMenu = subMenu;
				}				
				
				subMenu.setCreatedDate( cale.getTime() );
				subMenu.setCreatedUserId(initDataUser);
				subMenu.setUpdatedDate( cale.getTime() );
				subMenu.setUpdatedUserId(initDataUser);
				subMenu.setOwnedUserId( initDataUser );				

				
				// --- get the same parent group ---					
				try {

					if (menu.getParentId()  != null && !menu.getParentId().trim().equals("")) {
						// --- get parent menu for parent id ---
						org.vsg.biz.account.Menu parentMenu = existedMenus.get(menu.getParentId() );
						
						if (parentMenu != null) {
							int menuLevel = parentMenu.getMenuLevel() + 1;
							String treeMap = parentMenu.getTreeMap() == null ? "" : parentMenu.getTreeMap();
							if (treeMap != null && treeMap.length() > 0 ) {
								treeMap += "-";
							}
							
						} else {

							mnuParentKeyMap.put( subMenu.getId() , menu.getParentId() );
							
							Set<org.vsg.biz.account.Menu> theSameGroup = parentMnuGroup.get( menu.getParentId() );
							if (theSameGroup == null) {
								theSameGroup = new LinkedHashSet<org.vsg.biz.account.Menu>();
							}
							theSameGroup.add(subMenu);
							parentMnuGroup.put( menu.getParentId() , theSameGroup);	
							
						}
						
					}
					
					
					if (!newMenuMap.keySet().contains( subMenu.getId() )) {
						newMenuMap.put( subMenu.getId() , subMenu);
					}
					
					
				} finally {
					
				}

				
		
				
				// --- map the ref-key ---
				if (!menu.isModuleMenu()) {
					ResourceRef  bindingRef =  menu.getRefKey();
					if (bindingRef != null) {
						RegisterResource menuRegRes =  moduleRegisterManager.getResourceById( bindingRef.getRefid() , proxy.getModule().getId());
						if (menuRegRes != null) {
							subMenu.setKeyAction( resourceProtocol.encodeKeyAction(menuRegRes) );
						}
					}
					
				}


				modMenus.add( subMenu );
				existedMenuCodes.add( menu.getId() );

			}	
		}
		
		
		// --- update new module menu ---
		for (org.vsg.biz.account.Menu menu :  modMenus) {
			
			// --- set parent value ---
			if (mnuParentKeyMap.keySet().contains( menu.getId() )) {
				String parentId = mnuParentKeyMap.get( menu.getId() );
				org.vsg.biz.account.Menu parent = newMenuMap.get( parentId );
				
				// --- set level ---
				int parentLevel = 0;
				int currentLevel = 0;
				if (parent != null) {
					
					menu.setParent(parent);
					parentLevel = parent.getMenuLevel();
					currentLevel = parentLevel+1;
				}  else {
					if ( logger.isWarnEnabled() ) {
						logger.warn("Not found parent menu for menu id [" + parentId+"]");
					}					
				}
				
				menu.setMenuLevel( currentLevel);
			}			
			
			if (menu.getParent() != null) {
				String parentId = menu.getParent().getId();
				
				// --- find tree path from root ---
				StringBuilder path = new StringBuilder();
				String parIdInPath = parentId;
				do {
					
					if (path.length() > 0) {
						path.insert(0, parIdInPath+"-");
					} else {
						path.insert(0,parIdInPath);						
					}

					
					parIdInPath = mnuParentKeyMap.get( parIdInPath );
					
				} while (parIdInPath != null);
				menu.setTreeMap( path.toString() );
				
				menu.setMenuLevel( menu.getParent().getMenuLevel() + 1 );
			}
		}
		
		// --- sort by parent menu-level---
		
		return modMenus;
		
	}

	
	private Set<org.vsg.biz.account.Url> initUnloadedUrls(Set<String> funIds ,Set<org.vsg.biz.account.Module> regModules ) {

		Set<String> moduleIds = new LinkedHashSet<String>();
		for (org.vsg.biz.account.Module mod : regModules ) {
			moduleIds.add( mod.getId() );
		}
		
		Map<String, Url> urlMap = urlRepo.findAllByModuleIds( moduleIds );
		
	
		Set<String> existedUrlCodes = new LinkedHashSet<String>(urlMap.keySet());		
		
		Set<org.vsg.biz.account.Url> newUrls = new LinkedHashSet<org.vsg.biz.account.Url>();
		
		Calendar cale = Calendar.getInstance();
		
		// --- build new menu and find the other menu ---
		for (org.vsg.biz.account.Module module : regModules) {
			
			ModuleProxy proxy = proxiesMap.get( module.getId() );
			
			// ---- check the function module first --
			if (proxy == null) {
				continue;
			}

			Set<ModuleFunction> modFuns = moduleRegisterManager.listFunsInMoudle( proxy.getModule() );
			
			for (Iterator<ModuleFunction> unloadedFunIter = modFuns.iterator() ; unloadedFunIter.hasNext() ; ) {
				
				ModuleFunction modFun = unloadedFunIter.next();
				
				// --- find match function key --
				String uuidForFun = null;
				for (String funId : funIds) {
					if (funId.equals( modFun.getId() ) ) {
						uuidForFun = funId;
					}
				}

				Set<AssociationClass> assoClses = moduleRegisterManager.listAssoClassInFunction( modFun );				
				
				for (AssociationClass assoCls : assoClses) {
					
					if (existedUrlCodes.contains( assoCls.getId()) ) {
						continue;
					}

					
					org.vsg.biz.account.Url url = entityFactory.create( org.vsg.biz.account.Url.class );
					url.setId( assoCls.getId() );
					url.setCode( assoCls.getFullKey() );
					url.setModuleId( module.getId());
					url.setFunctionId( uuidForFun );
					url.setType("internal");
					url.setLocked( assoCls.getLocked() );
					
					
					String link = findLink(assoCls.getClassName() ,  assoCls.getValue());
					if ( link != null) {
						url.setLink( link );
					}
					
					if ( ! (proxy.getModule().isEnabledStatus() && proxy.getModule().isBootup() ) ) {
						url.setDisabled( (short)1 );
					} 
					
					url.setCreatedDate( cale.getTime() );
					url.setCreatedUserId(  initDataUser );
					url.setUpdatedDate( cale.getTime() );
					url.setUpdatedUserId( initDataUser );
					url.setOwnedUserId( initDataUser );
					
					existedUrlCodes.add( assoCls.getId());
					
					newUrls.add( url );

				}				
			}
			
			

			// --- add module menu for url ---
			Set<AssociationClass> unRegAssoCls = moduleRegisterManager.listAssoClassInModule( proxy.getModule() );
			
			for (AssociationClass assoCls : unRegAssoCls) {
				
				if (existedUrlCodes.contains( assoCls.getId()) ) {
					continue;
				}

				
				org.vsg.biz.account.Url url = entityFactory.create( org.vsg.biz.account.Url.class );
				url.setId( assoCls.getId() );
				url.setCode( assoCls.getFullKey() );
				url.setModuleId( module.getId() );
				url.setType("internal");
				url.setLocked( assoCls.getLocked() );
				
				
				String link = findLink(assoCls.getClassName() ,  assoCls.getValue());
				if ( link != null) {
					url.setLink( link );
				}
				
				if ( ! (proxy.getModule().isEnabledStatus() && proxy.getModule().isBootup() ) ) {
					url.setDisabled( (short)1 );
				} 
				
				url.setCreatedDate( cale.getTime() );
				url.setCreatedUserId(  initDataUser );
				url.setUpdatedDate( cale.getTime() );
				url.setUpdatedUserId( initDataUser );
				url.setOwnedUserId( initDataUser );	
				
				newUrls.add( url );
				existedUrlCodes.add(assoCls.getId() );

			}
			
			// --- find for function ---
		
		}
		return newUrls;
		
	}	


	
	private Set<org.vsg.biz.account.BindingAction> initAndMergeBindingAction(Set<org.vsg.biz.account.Resource> resIncludeBinding , Set<org.vsg.biz.account.Module> unloadModules ) {
		
		Set<org.vsg.biz.account.BindingAction> actionBindingSet = new LinkedHashSet<org.vsg.biz.account.BindingAction>();
		
		// --- predefined resource mapping ---
		Map<String , org.vsg.biz.account.Resource> mapping = new LinkedHashMap<String , org.vsg.biz.account.Resource>();
		for (org.vsg.biz.account.Resource sysRes : resIncludeBinding) {
			mapping.put( sysRes.getId(), sysRes);
		}
		
		
		// --- load modules ---
		org.vsg.biz.account.Module smodule = null;

		for (Iterator<org.vsg.biz.account.Module> unloadedIter = unloadModules.iterator() ; unloadedIter.hasNext() ; ) {
			smodule = unloadedIter.next();
			
			ModuleProxy proxy = proxiesMap.get( smodule.getId() );
			
			Module module = proxy.getModule();
			
			Set<ModuleFunction> modFuns = moduleRegisterManager.listFunsInMoudle( module) ;
			
			// --- function module ---
			for (RegisterResource res : modFuns) {
				RegisterResource  parentRegRes =moduleRegisterManager.getResourceById( res.getId(), module.getId() );

				org.vsg.biz.account.BindingAction actBa = entityFactory.create( org.vsg.biz.account.BindingAction.class ) ;
				String resCode = res.getId();
				
				actBa.setAssoRes( mapping.get( resCode )  );
				actBa.setAction( resourceProtocol.encodeKeyAction(parentRegRes) );				
				
				actionBindingSet.add( actBa );
				
				Set<ResourceRef> closeallBindRefes =  moduleRegisterManager.findAllBindingRefsById( res.getId() ,  module.getId() );
				
				for ( ResourceRef closeBr : closeallBindRefes) {
					
					RegisterResource  regRes = moduleRegisterManager.getResourceById( closeBr.getRefid() , module.getId() );
					
					if ( regRes != null) {
						BindingAction act = entityFactory.create( org.vsg.biz.account.BindingAction.class ) ;
						
						act.setAssoRes( mapping.get( res.getId() ) );
						
						String parseAct = resourceProtocol.encodeKeyAction(regRes);
						act.setAction( parseAct );

						actionBindingSet.add( act );
						
					}
				}				
				
			}
			
			Set<Menu> menus =  moduleRegisterManager.listMenusInModule( module) ;

			// --- function module ---
			for (RegisterResource res : menus) {
				RegisterResource  parentRegRes =moduleRegisterManager.getResourceById( res.getId(), module.getId() );

				
				BindingAction actBa = entityFactory.create( org.vsg.biz.account.BindingAction.class ) ;
				
				String resCode = res.getId();
				
				actBa.setAssoRes( mapping.get( resCode )  );
				actBa.setAction( resourceProtocol.encodeKeyAction(parentRegRes) );				
				
				actionBindingSet.add( actBa );
				
				Set<ResourceRef> closeallBindRefes =  moduleRegisterManager.findAllBindingRefsById( res.getId() ,  module.getId() );
				
				for ( ResourceRef closeBr : closeallBindRefes) {
					
					RegisterResource  regRes = moduleRegisterManager.getResourceById( closeBr.getRefid() , module.getId() );
					
					if (regRes != null) {
						BindingAction act = entityFactory.create( org.vsg.biz.account.BindingAction.class ) ; 
						
						act.setAssoRes( mapping.get( res.getId() ) );
						
						String parseAct = resourceProtocol.encodeKeyAction(regRes);
						act.setAction( parseAct );

						actionBindingSet.add( act );
						
					}
					
				}				
			}			
		}

		
		return actionBindingSet;

	}
	
	
	/**
	 * permission handle
	 * @param registerModules
	 * @return
	 */
	private Set<org.vsg.biz.account.Permission> initPermissions(Set<org.vsg.biz.account.Module> registerModules) {

		// --- find resource ---
		org.vsg.biz.account.Role role = roleRepo.findOneByCode( initSystemRole );
		
		Set<org.vsg.biz.account.Permission> newperms = new LinkedHashSet<org.vsg.biz.account.Permission>();
		
		// --- build new menu and find the other menu ---
		for (org.vsg.biz.account.Module module : registerModules) {
			
			ModuleProxy proxy = proxiesMap.get( module.getId() );
		
			Set<String> reses = sysResourceDao.findPermCodes(module.getId(), initSystemRole);
			Set<org.vsg.biz.account.Resource> resesInModule = sysResourceDao.findInModule( module.getId());
			
			// --- get all permission ---
			Set<Permission> unCheckPermissions = moduleRegisterManager.listPermsInModule( proxy.getModule() );
			for (Permission perm : unCheckPermissions) {
				String refId = perm.getRefId();
				RegisterResource res = moduleRegisterManager.getResourceById(refId, proxy.getProxyId());
				
				if (res == null) {
					continue;
				}
				
				String registerResCode= res.getId();
				boolean hasPerm = reses.contains( res.getId() );
				
				if ( !hasPerm) {
					// --- add resource ---
					
					org.vsg.biz.account.Resource resWithoutPerm = null;
					for (Iterator<org.vsg.biz.account.Resource> resIter = resesInModule.iterator() ; resIter.hasNext() ; ) {
						resWithoutPerm = resIter.next();
						
						String codewithoutPerm = resWithoutPerm.getId();
					
						if ( registerResCode.equals( codewithoutPerm )) {
							// --- binding new permission ---
							if (perm.getAcl() != null && perm.getActId() == null)  {
								org.vsg.biz.account.Permission  p = entityFactory.create( org.vsg.biz.account.Permission.class ) ; 
								p.setAssignedResource( resWithoutPerm );
								p.setAssignedRole( role );
								p.setAccessControl( perm.getAcl() );
								// --- add permission data --
								newperms.add(p);
							}
							else if (perm.getActId() != null) {
								
								// --- grant function permiession ---
								org.vsg.biz.account.Permission  funPerm = entityFactory.create( org.vsg.biz.account.Permission.class ) ; 
								funPerm.setAssignedResource( resWithoutPerm );
								funPerm.setAssignedRole( role );
								funPerm.setBindingActionId( perm.getActId() );
								// --- add permission data --
								newperms.add(funPerm);
								
								
								// --- get action ---
								Action act = moduleRegisterManager.getActionInModule(perm.getActId(), proxy.getModule());
								Set<PermDefine> permDefSet = moduleRegisterManager.listPermDefine(act);
								for (PermDefine pd : permDefSet) {
									org.vsg.biz.account.Resource refRes = sysResourceDao.findOne( pd.getRefId()  );
									
									if (refRes == null) {
										if ( logger.isDebugEnabled() ) {
											logger.debug("Found Resouce is null for refid = " + pd.getRefId() );
										}
										continue;
									}
									org.vsg.biz.account.Permission  p = entityFactory.create( org.vsg.biz.account.Permission.class ) ; 

									p.setAssignedResource( refRes );
									p.setAssignedRole( role );
									p.setAccessControl( pd.getAcl() );
									// --- add permission data --
									newperms.add(p);
									
								}
							}
							
						}
					}					
				}
			}

		}

		return newperms;
	}
	
	
	private String findLink(String clsName , String key) {
		
		try {
			Class cls = Class.forName( clsName );
			
			RequestMapping classMapping = AnnotationUtils.findAnnotation(cls,  RequestMapping.class);
			
			String basePath = null;
			if ( classMapping != null ) {
				String[] values = classMapping.value();
				basePath = values[0];
			}

			// --- scan the bean method ---
			for (Method beanMethod : cls.getMethods() ) { 
				
				// --- find the request mapping ---
				RequestMapping methodMapping = AnnotationUtils.findAnnotation(beanMethod,  RequestMapping.class);				
				StringBuilder builder = null;
				if ( basePath == null) {
					builder = new StringBuilder();
				} else {
					builder = new StringBuilder(basePath);
				}
				if ( methodMapping != null) {
					String[] values = methodMapping.value();
					for (String endPath : values) {
						if ( endPath.startsWith("/")) {
							builder.append(endPath);
						} else {
							builder.append("/").append(endPath);
						}
					}
				}

				RegisterRequestPermissionStrategy ps = beanMethod.getAnnotation( RegisterRequestPermissionStrategy.class );
				if ( ps != null && ps.value().equals(key) ) {
					return builder.toString();
				}


			};
			
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}	

	
}
